<?php


/**
 *
 *
 * @author adriano
 *
 */
class ShopProduct {

	// only primitive values are allowed.
	// it is not possible to set a value on a constant once it has been declared
	const AVAILABLE		= 0;
	const OUT_OF_STOCK	= 1;

	private 	$title;
	private 	$firstName;
	private 	$producerMainName;
	private 	$producerFirstName;
	private 	$price;
	private 	$discount			= 0;
	private 	$id = 0;


	/**
	 * Constructor
	 * Enter description here ...
	 * @param unknown_type $title
	 * @param unknown_type $firstName
	 * @param unknown_type $mainName
	 * @param unknown_type $price
	 */
	function __construct($title, $firstName, $mainName, $price) {
		$this->title 				= $title;
		$this->producerMainName 	= $mainName;
		$this->producerFirstName	= $firstName;
		$this->price				= $price;
	}



	// ACCESS METHODS
	public function setID( $id ) {
		$this->id = $id;
	}

	public function getProducerFirstName() {
		return $this->producerFirstName;
	}

	public function getProducerMainName() {
		return $this->producerMainName;
	}

	public function setDiscount( $num ) {
		$this->discount=$num;
	}

	public function getDiscount() {
		return $this->discount;
	}

	public function getTitle() {
		return $this->title;
	}

	public function getPrice() {
		return ($this->price - $this->discount);
	}

	public function getProducer() {
		return "{$this->producerFirstName}".
		" {$this->producerMainName}";
	}



	function getSummaryLine() {
		$base  = "$this->title ( $this->producerMainName, ";
		$base .= "$this->producerFirstName )";
		return $base;
	}



}



class CdProduct extends ShopProduct{
	private $playLength = 0;

	public function __construct($title, $firstName, $mainName, $price, $playlength) {
		parent::__construct($title, $firstName, $mainName, $price);
		$this->playLength = $playlength;
	}

	public function getPlayLength() {
		return $this->playLength;
	}

	function getSummaryLine() {
		$base = parent::getSummaryLine();
		$base .= ": playing time - $this->playLength";
		return $base;
	}

}






class BookProduct extends ShopProduct {
	private $numPages = 0;

	public function __construct(   $title, $firstName,
	$mainName, $price, $numPages ) {
		parent::__construct(    $title, $firstName,
		$mainName, $price );
		$this->numPages = $numPages;
	}

	public function getNumberOfPages() {
		return $this->numPages;
	}

	function getSummaryLine() {
		$base = parent::getSummaryLine();
		$base .= ": page count - $this->numPages";
		return $base;
	}

	public function getPrice() {
		return $this->price;
	}
}




/**
 *
 * Areas of responsability.
 * This class is resonsible for writing  while the responsability of the class ShopProduct
 * is to manage product data.
 * @author adriano
 *
 */
class SimpleProductWriter {

	/**
	 *
	 * Class type hints added to php5. In this example only objects of type ShopProduct
	 * will be accepted.
	 * @param ShopProduct $shopProduct
	 */
	public function write(ShopProduct $shopProduct ) {
		$str  = "{$shopProduct->title}: " .
		$shopProduct->getProducer() .
                " ({$shopProduct->price})\n";
		print $str;
	}
}




abstract class ShopProductWriter {
	protected $products = array();

	public function addProduct( ShopProduct $shopProduct ) {
		$this->products[]=$shopProduct;
	}

	/**
	 *
	 * With the creation of an abstract method we ensure than an implementation will be implemented
	 * in the child class
	 */
	abstract public function write( );
}

/**
 *
 * Any class that extends an abstract class must implemt all abstract methods
 * @author adriano
 *
 */
class XmlProductWriter extends ShopProductWriter{
	public function write() {
		$str = '<?xml version="1.0" encoding="UTF-8"?>'."\n";
		$str .= "<products>\n";
		foreach ( $this->products as $shopProduct ) {
			$str .= "\t<product title=\"{$shopProduct->getTitle()}\">\n";
			$str .= "\t\t<summary>\n";
			$str .= "\t\t{$shopProduct->getSummaryLine()}\n";
			$str .= "\t\t</summary>\n";
			$str .= "\t</product>\n";
		}
		$str .= "</products>\n";
		print $str;
	}
}


/**
 *
 * A diferent implementations of the write abstract function
 * @author adriano
 *
 */
class TextProductWriter extends ShopProductWriter{
	public function write() {
		$str = "PRODUCTS:\n";
		foreach ( $this->products as $shopProduct ) {
			$str .= $shopProduct->getSummaryLine()."\n";
		}
		print $str;
	}
}


// create products
$product1 = new BookProduct("Teixeira", "antonio", "main", 5.99, 300);
$product2 = new CdProduct("cd title", "cd firstname", "cd main name", 10, 60);


function printText() {
	global $product1,$product2;
	$textwriter = new TextProductWriter();
	$textwriter->addProduct($product1);
	$textwriter->addProduct($product2);
	$textwriter->write();
}

function printXML() {
	global $product1,$product2;
	$xmlwriter = new XmlProductWriter();
	$xmlwriter->addProduct( $product1 );
	$xmlwriter->addProduct( $product2 );
	$xmlwriter->write();
}


// printText();


class Person {
	private $name;
	private $age;
	private $id;

	function __construct($name,$age) {
		$this->name = $name;
		$this->age	= $age;
	}

	function setId($id) {
		$this->id = $id;
	}

	function __destruct() {
		if (!empty($this->id))
		print "saving person\n";
	}
}

function testPerson() {
	$person = new Person("bob", 30);
	$person->setId(300);
	unset($person);
}

testPerson();




?>